module denetim;

import std.algorithm;
import std.string;

/*
 * Sıradüzenin en üstündeki bu sınıf yalnızca kullanıcıya bildirilecek olan
 * mesajı barındırır.
 */
class Denetim
{
    // Denetim geçersiz olduğunda kullanıcıya bildirilen mesaj
    string mesaj_;

    this(string mesaj)
    {
        mesaj_ = mesaj;
    }

    string mesaj() const @property
    {
        return mesaj_;
    }

    /* Bu işlevin tanımı özel denetimlerine bağlı olarak alt sınıflar
     * tarafından yapılır. */
    abstract bool yasal_mı(dstring tutulan) const;
}

unittest
{
    // Mesajın geri okunabildiğini test edelim
    class Deneme : Denetim
    {
        this()
        {
            super("deneme mesajı");
        }

        override bool yasal_mı(dstring tutulan) const
        {
            return true;
        }
    }

    auto denetim = new Deneme;
    assert(denetim.mesaj == "deneme mesajı");
}

class YasalRakamDenetimi : Denetim
{
    dstring geçerliRakamlar;

    this(dstring geçerliRakamlar)
    {
        super(format("Geçerli rakamlar: %s", geçerliRakamlar));
        this.geçerliRakamlar = geçerliRakamlar;
    }

    override bool yasal_mı(dstring tutulan) const
    {
        return !(tutulan.canFind!(a => !geçerliRakamlar.canFind(a)));
    }
}

unittest
{
    Denetim denetim = new YasalRakamDenetimi("abçdefg");
    assert( denetim.yasal_mı("açf"));   // doğru rakamlar
    assert(!denetim.yasal_mı("azğ"));   // geçersiz rakam
}

class RakamTekrarıDenetimi : Denetim
{
    this()
    {
        super("Rakam tekrarlanamaz");
    }

    override bool yasal_mı(dstring tahmin) const
    {
        foreach (i, tahminRakamı; tahmin[0 .. $ - 1]) {
            if (canFind(tahmin[i + 1 .. $], tahminRakamı)) {
                return false;
            }
        }

        return true;
    }
}

unittest
{
    Denetim denetim = new RakamTekrarıDenetimi;
    assert( denetim.yasal_mı("aoeuhtsnüö"));   // tekrar yok
    assert(!denetim.yasal_mı("aoEuhtsEnÜÖ"));  // tekrar var
}

class HaneAdediDenetimi : Denetim
{
    size_t haneAdedi;

    this(size_t haneAdedi)
    {
        super(format("Lütfen %s hane giriniz", haneAdedi));
        this.haneAdedi = haneAdedi;
    }

    override bool yasal_mı(dstring tahmin) const
    {
        return tahmin.length == haneAdedi;
    }
}

unittest
{
    Denetim denetim = new HaneAdediDenetimi(7);
    assert( denetim.yasal_mı("1234567"));    // evet, 7 haneli
    assert( denetim.yasal_mı("123ü567"));    // evet, 7 haneli
    assert(!denetim.yasal_mı("ö23456"));     // 7 değil
    assert(!denetim.yasal_mı("12345678"));   // 7 değil
}
